﻿using System;
using System.Collections.Generic;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using QRCodePass.Application;
using QRCodePass.Application.QRCode;
using QRCodePass.Application.QRCode.Dtos;
using QRCodePass.Core.Extensions;
using QRCodePass.Core.Models;
using QRCodePass.Core.Repositories;
using QRCodePass.Mvc.Controllers;
using QRCodePass.Mvc.Security.CustomTokenProvider;
using QRCodePass.Mvc.ViewModels.Account;
using QRCodePass.Mvc.ViewModels.Process;
using QRCodePass.Mvc.ViewModels.Sudent;
using QRCodePass.Mvc.ViewModels.Task;

namespace QrCodePass.Mvc.Controllers
{
    [AllowAnonymous]
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class QrCodeProcController : BaseController
    {
        private readonly IRepository<Student, int> _studentRepository;
        private readonly IRepository<Process, int> _processRepository;
        private readonly IRepository<StudentProcess, int> _recordRepository;
        private readonly IRepository<DepartProc, int> _departProcRepository;
        private readonly IRepository<Department, int> _departmentRepository;
        private readonly IRepository<Build, int> _buildRepository;
        private ILogger<AccountController> _logger;
        private SignInManager<ApplicationUser> _signInManager;
        private readonly IDataProtector _protector;
        private readonly IQRCodeService _qRCodeService;
        private readonly UserManager<ApplicationUser> _userManager;
        public QrCodeProcController(
            UserManager<ApplicationUser> userManager,
            SignInManager<ApplicationUser> signInManager,
            ILogger<AccountController> logger,
            IDataProtectionProvider dataProtectionProvider,
            DataProtectionPurposeStrings dataProtectionPurposeStrings,
            IRepository<Student, int> studentRepository,
            IRepository<Process, int> processRepository,
            IRepository<StudentProcess, int> recordRepository,
            IRepository<DepartProc, int> departProcRepository,
            IRepository<Department, int> departmentRepository,
            IRepository<Build, int> buildRepository,
            IQRCodeService qRCodeService)
        {
            _logger = logger;
            _protector = dataProtectionProvider.CreateProtector(
                dataProtectionPurposeStrings.StudentPwdRouteValue);
            _studentRepository = studentRepository;
            _processRepository = processRepository;
            _recordRepository = recordRepository;
            _departProcRepository = departProcRepository;
            _departmentRepository = departmentRepository;
            _buildRepository = buildRepository;
            _qRCodeService = qRCodeService;
            _signInManager = signInManager;
            _userManager = userManager;
        }

        /// <summary>
        /// 登录接口
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<OperateResult> Login([FromForm] ApiLoginViewModel model)
        {
            //请求参数验证
            if (!ModelState.IsValid) return OperateResult.Failed("账号及密码不允许为空");
            var student = await _studentRepository.FirstOrDefaultAsync(x => x.StudentNo == model.StudentNo);
            if (student == null) return OperateResult.Failed("登录学生不存在");
            if (!model.Password.Equals(AESEncryptExtension.AesDecrypt(student.Pwd))) return OperateResult.Failed("账号或密码不正确");

            //返回模型数据
            var detail = new StudentDetailViewModel()
            {
                DepartmentId = student.DepartmentId,
                BuildId = student.BuildId,
                Email = student.Email,
                StudentNo = student.StudentNo,
                EnrollmentDate = student.EnrollmentDate,
                Id = student.Id,
                Major = student.Major,
                MajorName = student.Major.GetDisplayName(),
                Name = student.Name,
                PhotoPath = student.PhotoPath
            };
            return OperateResult.Successed(detail);
        }

        /// <summary>
        /// 管理员登录接口
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<OperateResult> AdminLogin([FromForm] LoginViewModel model)
        {
            //请求参数验证
            var user = await _userManager.FindByEmailAsync(model.Email);
            var processList = new List<Process>(); //任务列表

            if (user != null && !user.EmailConfirmed &&
                (await _userManager.CheckPasswordAsync(user, model.Password)))
            {
                return OperateResult.Failed("您的电子邮箱还未进行验证。");
            }
            //返回模型数据
            var result = await _signInManager.PasswordSignInAsync(
                model.Email, model.Password, model.RememberMe, true);
            if (result.Succeeded)
            {
                //获取该用户拥有的所有的权限
                var taskList = user.ProcessList.Split(',').ToList().ConvertAll(s => int.Parse(s));//用户拥有的
                var allTask = _processRepository.GetAllList();//所有的流程
                var query = from item in allTask
                            where taskList.Contains(item.Id)
                            select item;
                foreach (var item in query)
                {
                    Process proc = new Process()
                    {
                        Id = item.Id,
                        PreTask = item.PreTask,
                        ProcName = item.ProcName,
                        BuildId = item.BuildId,
                        Builds = item.Builds,
                        //Departments = item.Departments,
                        Description=item.Description
                    };
                    processList.Add(proc);
                }
                AdminTaskListViewModel adminTaskList = new AdminTaskListViewModel()
                {
                    Admin = user,
                    CanProcessList = processList
                };
                return OperateResult.Successed(adminTaskList);
            }
            //如果账户状态为IsLockedOut，那么我们重定向到AccountLocked视图，提示用户账号被锁定。
            if (result.IsLockedOut)
            {
                return OperateResult.Failed("该账户已锁定！");
            }
            return OperateResult.Failed("账号或密码错误，请重试");
        }

        /// <summary>
        /// 完成报道接口
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<OperateResult> CompleteTask(TaskViewModel model)
        {
            if (!ModelState.IsValid) return OperateResult.Failed();
            if (model.RecordTime.Equals(DateTime.MinValue) || model.RecordTime < DateTime.Now.AddMinutes(-1))
            {
                return OperateResult.Failed("二维码已经过期！");
            }
            try
            {
                var student = await _studentRepository.FirstOrDefaultAsync(x => x.StudentNo == model.StudentNo);
                var user = await _userManager.FindByIdAsync(model.PersonId);
                var process = await _processRepository.FirstOrDefaultAsync(x => x.Id == model.ProcessId);

                if (student == null || process == null) return OperateResult.Failed("无对应学生或流程！");
                {
                    //验证是否重复添加
                    var resultAsync = await _recordRepository.FirstOrDefaultAsync(x =>
                        x.ProcessId == process.Id && x.StudentId == student.Id);
                    if (resultAsync != null) return OperateResult.Failed("勿重复提交！");
                    StudentProcess studentProcess = new StudentProcess()
                    {
                        StudentId = student.Id,
                        ProcessId = process.Id,
                        RecordTime = model.RecordTime == DateTime.MinValue ? DateTime.Now : model.RecordTime,
                        RecordPerson = user.UserName
                    };
                    var insertAsync = await _recordRepository.InsertAsync(studentProcess);
                    if (insertAsync.RecordId!=0)
                    {
                        return OperateResult.Success;
                    }
                    else
                    {
                        return OperateResult.Failed("错误！联系管理员");
                    }
                  
                }
            }
            catch (Exception e)
            {
                return OperateResult.Failed(e.Message);
            }
        }

        /// <summary>
        /// 获取流程列表
        /// </summary>
        /// <param name="studentNo"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<OperateResult> GetTask([FromForm] string studentNo)
        {
            if (!ModelState.IsValid) return OperateResult.Failed();
            var processList = new List<Process>(); //任务列表
            var unFinshIds = new List<int>(); //未完成前置任务列表
            var finshIds = new List<int>(); //完成前置任务列表
            TaskStateViewModel viewModel = new TaskStateViewModel();
            viewModel.StudentNo = studentNo;
            try
            {
                var studentModel = await _studentRepository.FirstOrDefaultAsync(x => x.StudentNo == viewModel.StudentNo);
                var process = await _processRepository.GetAllListAsync();
                var students = await _studentRepository.GetAllListAsync();
                var departProcList = await _departProcRepository.GetAllListAsync();
                var recordList = await _recordRepository.GetAllListAsync();
                //查询学生的流程列表
                var query = from student in students
                            join departProc in departProcList on student.DepartmentId equals departProc.DepartmentId
                            join proc in process on departProc.ProcessId equals proc.Id
                            where student.StudentNo == viewModel.StudentNo
                            select new
                            {
                                StudentId = student.Id,
                                student.StudentNo,
                                proc.ProcName,
                                proc.PreTask,
                                ProcessId = proc.Id,
                                departProc.DepartmentId
                            };

                //学生是否完成当前流程
                foreach (var item in query)
                {
                    Process proc = new Process()
                    {
                        Id = item.ProcessId,
                        PreTask = item.PreTask,
                        ProcName = item.ProcName
                    };
                    processList.Add(proc);
                    //是否完成前置任务
                    if (recordList.Find(x => x.ProcessId == item.PreTask && x.StudentId == item.StudentId) == null)
                    {
                        unFinshIds.Add(item.ProcessId);//添加未完成列表
                    }
                    else
                    {
                        //是否完成当前任务
                        if (recordList.Find(x => x.ProcessId == item.ProcessId && x.StudentId == item.StudentId) !=
                            null)
                        {
                            finshIds.Add(item.ProcessId);//添加完成任务列表
                        }
                        else
                        {
                            //是否为前置任务   完成了前置任务，但是没有完成当前任务
                            viewModel.PreTaskId = item.ProcessId;//设置当前为前置任务
                        }

                    }
                }
                viewModel.FinshId = finshIds;
                viewModel.UnFinshId = unFinshIds;
                viewModel.Processes = processList.OrderBy(x => x.Id).ToList();

                //按钮是否已选定
                return OperateResult.Successed(viewModel);
            }
            catch (Exception e)
            {
                return OperateResult.Failed(e.Message);
            }
        }

        /// <summary>
        /// 获取流程详情
        /// </summary>
        /// <param name="processId"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<OperateResult> GeTaskDetail([FromForm] int processId)
        {
            var process = await _processRepository.FirstOrDefaultAsync(x => x.Id == processId);
            if (process != null)
            {
                var build = process.Builds;
                var preTask = await _processRepository.FirstOrDefaultAsync(x => x.Id == process.PreTask);
                TaskDetailViewModel model = new TaskDetailViewModel()
                {
                    Build = build,
                    Description = process.Description,
                    Id = process.Id,
                    BuildId = build.Id,
                    PreTask = process.PreTask,
                    PreTaskName = preTask.ProcName,
                    ProcName = process.ProcName
                };
                return OperateResult.Successed(model);
            }
            return OperateResult.Failed("失败");
        }

        /// <summary>
        /// 获取学生详情
        /// </summary>
        /// <param name="studentId">学生的Id</param>
        /// <returns></returns>
        [HttpPost]
        public async Task<OperateResult> GetStudentDetail([FromForm] int studentId)
        {
            var student = await _studentRepository.FirstOrDefaultAsync(x => x.Id == studentId);
            if (student != null)
            {
                var department = await _departmentRepository.FirstOrDefaultAsync(x => x.Id == student.DepartmentId);
                var build = await _buildRepository.FirstOrDefaultAsync(x => x.Id == student.BuildId);
                if (department == null || build == null) return OperateResult.Failed("未找到学生对应的楼栋及系部，请检查数据");
                var detail = new StudentDetailViewModel()
                {
                    DepartmentName = department.Name,
                    DepartmentId = department.Id,
                    BuildName = build.Name,
                    BuildId = build.Id,
                    Email = student.Email,
                    StudentNo = student.StudentNo,
                    EnrollmentDate = student.EnrollmentDate,
                    Id = studentId,
                    Major = student.Major,
                    MajorName = student.Major.GetDisplayName(),
                    Name = student.Name,
                    PhotoPath = student.PhotoPath
                };
                return OperateResult.Successed(detail);
            }
            return OperateResult.Failed();
        }

        /// <summary>
        /// 获取某人的权限
        /// </summary>
        /// <param name="personId"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<OperateResult> GetPersonPower([FromForm] string personId)
        {
           var person=await  _userManager.FindByIdAsync(personId);
            return OperateResult.Successed(person);
        }


        /// <summary>
        /// 获取二维码
        /// </summary>
        /// <param name="studentId"></param>
        /// <param name="date"></param>
        /// <returns></returns>
        [HttpGet]
        public async void GetQrCode(int studentId, string date)
        {
            Response.ContentType = "image/jpeg";
            System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)); // 当地时区
            DateTime newDateTime = startTime.AddMilliseconds(long.Parse(date));
            QrResponse response = new QrResponse()
            {
                StudentId = studentId,
                RecordTime = newDateTime
            };
            var content = JsonConvert.SerializeObject(response);
            var aesEncryptContent = AESEncryptExtension.AesEncrypt(content);
            var bitmap = _qRCodeService.GetQRCode(aesEncryptContent, 4);
            MemoryStream msStream = new MemoryStream();
            bitmap.Save(msStream, ImageFormat.Jpeg);

            await Response.Body.WriteAsync(msStream.GetBuffer(), 0, Convert.ToInt32(msStream.Length));
            Response.Body.Close();
        }

        /// <summary>
        /// 解密方法
        /// </summary>
        /// <param name="encrypt">密文</param>
        /// <returns></returns>
        [HttpGet]
        public OperateResult Decrypt(string encrypt)
        {
            string decryptStr = AESEncryptExtension.AesDecrypt(encrypt);
            StudentEncryptViewModel result = JsonConvert.DeserializeObject<StudentEncryptViewModel>(decryptStr);
            return OperateResult.Successed(result);
        }
    }
}
